﻿#ifndef _TES_VECTOR3_H_
#define _TES_VECTOR3_H_

#include <assert.h>
#include <math.h>

class TesVector3
{
public:
	float x, y, z;

	TesVector3(float X = 0.0f, float Y = 0.0f, float Z = 0.0f)
	{
		x = X;
		y = Y;
		z = Z;
	}

	TesVector3& operator = (const TesVector3& that)
	{
		x = that.x;
		y = that.y;
		z = that.z;
		return *this;
	}

	void Zero()
	{
		x = 0.0f;
		y = 0.0f;
		z = 0.0f;
	}

	float Length() const
	{
		return sqrtf(x * x + y * y + z * z);
	}

	float SqrLength() const
	{
		return (x * x + y * y + z * z);
	}

	TesVector3 Normalize() const
	{
		float len = this->Length();
		assert(len != 0.0f);
		return TesVector3(x / len, y / len, z / len);
	}

	TesVector3 operator + (const TesVector3& that)
	{
		return TesVector3(x + that.x, y + that.y, z + that.z);
	}

	TesVector3 operator - (const TesVector3& that) const
	{
		return TesVector3(x - that.x, y - that.y, z - that.z);
	}

	TesVector3 operator -() const
	{
		TesVector3 Res = *this;
		Res.x = -Res.x;
		Res.y = -Res.y;
		Res.z = -Res.z;
		return Res;
	}

	TesVector3 Projection(const TesVector3& n) const
	{
		float nLength = n.Length();
		float k = (*this * n) / (nLength * nLength);
		n.Normalize();
		return n * k;
	}

	TesVector3 multiplyComponent(const TesVector3& that) 
	{
		return TesVector3(x * that.x, y * that.y, z * that.z);
	}

	TesVector3 operator * (float K) const
	{
		return TesVector3(x * K, y * K, z * K);
	}

	float operator * (const TesVector3& that) const
	{
		return (x * that.x + y * that.y + z * that.z);
	}

	TesVector3 CrossProduct(const TesVector3& that) const
	{
		TesVector3 Res;
		Res.x = y * that.z - z * that.y;
		Res.y = z * that.x - x * that.z;
		Res.z = x * that.y - y * that.x;
		return Res;
	}

	TesVector3 operator / (float K) const
	{
		assert(K != 0.0f);
		return TesVector3(x / K, y / K, z / K);
	}

	bool operator == (const TesVector3& that)
	{
		return (this->x == that.x && this->y == that.y && this->z == that.z);
	}

	float Distance(const TesVector3& that) const
	{
		float SqrDeltaX = (this->x - that.x) * (this->x - that.x);
		float SqrDeltaY = (this->y - that.y) * (this->y - that.y);
		float SqrDeltaZ = (this->z - that.z) * (this->z - that.z);
		return sqrtf(SqrDeltaX + SqrDeltaY + SqrDeltaZ);
	}

	void GetGlVec(float Vec[3])
	{
		Vec[0] = x;
		Vec[1] = y;
		Vec[2] = z;
	}

};

inline TesVector3 operator * (float K, const TesVector3& v)
{
	return TesVector3(v.x * K, v.y * K, v.y * K);
}

#endif